
package models.deprecated;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToOne;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import javax.persistence.TypedQuery;

import models.aaa.Tag;
import models.aaa.Url;
import play.db.jpa.JPA;

/**
 * 
 * @author laurent@opprecht.info
 */
// @Entity
// @Table(uniqueConstraints = { @UniqueConstraint(columnNames = { "about_id" }),
// @UniqueConstraint(columnNames = { "url_id" }) })
public class Description {

    public static class Finder {

        public TypedQuery<Description> createQuery(final String sql) {
            TypedQuery<Description> result = JPA.em().createQuery(sql, Description.class);
            return result;
        }

        public TypedQuery<Description> query(final String sql, final Object... parameters) {
            TypedQuery<Description> result = createQuery(sql);
            for (int i = 0; i < parameters.length; i++) {
                result.setParameter(i + 1, parameters[i]);
            }
            return result;
        }

        public TypedQuery<Description> with(final String text) {
            String sql = "SELECT e FROM Description e WHERE LOWER(e.name) like ? or LOWER(e.description) like ? ";
            String constraint = "%" + text.toLowerCase() + "%";
            return query(sql, constraint, constraint);
        }

        public TypedQuery<Description> query(final String sql) {
            return query(sql, new Object[] {});
        }

        public Description byId(final Long id) {
            return JPA.em().find(Description.class, id);
        }

        public Description byUrl(final Url url) {
            if (url == null) {
                return null;
            }
            if (url.getId() == null) {
                return null;
            }

            String sql = "SELECT e FROM Description e WHERE e.url = ?";
            List<Description> items = query(sql, url).getResultList();
            for (Description item : items) {
                return item;
            }
            return null;
        }

    }

    public static final Finder find             = new Finder();
    /**
     * 
     */
    @SuppressWarnings("unused")
    private static final long  serialVersionUID = 8744068302677756989L;

    public enum Type {

        EMPTY, ACTOR, ASSET, ACTIVITY, SPACE, COMMENT;
    }

    public static Description get(final String url) {
        return get(Url.get(url));
    }

    public static Description get(final Url url) {
        if (url == null) {
            return null;
        }
        Description result = find.byUrl(url); //
        result = (result == null) ? new Description(url) : result;
        return result;
    }

    public static boolean has(final String url) {
        return get(Url.get(url)) != null;
    }

    public static boolean has(final Description des) {
        if (des == null) {
            return false;
        }
        if (des.getId() == null) {
            return false;
        }
        return find.byId(des.getId()) != null;
    }

    public static boolean has(final Url url) {
        return get(url) != null;
    }

    @Id
    @GeneratedValue
    private Long                    id          = null;

    @Enumerated(EnumType.STRING)
    private Type                    type        = Type.EMPTY;

    @OneToOne(cascade = { CascadeType.PERSIST, CascadeType.DETACH, CascadeType.REMOVE }, fetch = FetchType.LAZY)
    private Url                     url         = null;

    @OneToOne(cascade = { CascadeType.PERSIST, CascadeType.DETACH, CascadeType.REMOVE }, fetch = FetchType.LAZY)
    private Url                     about       = null;

    private String                  uid         = null;
    private String                  lid         = null;
    private String                  dataset     = null;
    private String                  name        = null;
    private String                  description = null;
    private Date                    created     = null;
    private Date                    modified    = null;
    private boolean                 isValid     = false;

    @ManyToMany(cascade = { CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.DETACH, CascadeType.MERGE })
    private List<Tag>               tags        = new ArrayList<Tag>();

    @ManyToMany(targetEntity = Description.class, cascade = { CascadeType.PERSIST, CascadeType.DETACH,
            CascadeType.REFRESH, CascadeType.MERGE }, fetch = FetchType.LAZY)
    @JoinTable(name = "description_link", joinColumns = @JoinColumn(name = "from_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "to_id", referencedColumnName = "id"))
    private final List<Description> links       = new ArrayList<Description>();

    protected Description() {
        setCreated(setModified(new Date()));
    }

    protected Description(final Url url) {
        this();
        setUrl(url);
    }

    @PreUpdate
    @PrePersist
    protected void beforeSave() {
        modified = new Date();
        if (created == null) {
            created = modified;
        }
    }

    /**
     * @return the id
     */
    public Long getId() {
        return id;
    }

    /**
     * @param id
     */
    protected void setId(final Long id) {
        this.id = id;
    }

    /**
     * @return the type
     */
    public Type getType() {
        return type;
    }

    /**
     * @param type
     */
    public void setType(final Type type) {
        this.type = type;
    }

    /**
     * @return the data
     */
    public Url getUrl() {
        return url;
    }

    /**
     * @param data
     */
    public void setUrl(final Url value) {
        this.url = value;
    }

    /**
     * @return the about
     */
    public Url getAbout() {
        return about;
    }

    /**
     * @param about
     */
    public void setAbout(final Url about) {
        this.about = about;
    }

    /**
     * @param about
     */
    public void setAbout(final String about) {
        this.about = Url.get(about);
    }

    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * @param name
     */
    public void setName(final String name) {
        this.name = name;
    }

    /**
     * @return the description
     */
    public String getDescription() {
        return description;
    }

    /**
     * @param description
     */
    public void setDescription(final String description) {
        this.description = description;
    }

    /**
     * @return the created
     */
    public Date getCreated() {
        return created;
    }

    /**
     * @param created
     */
    protected void setCreated(final Date created) {
        this.created = created;
    }

    /**
     * @return the modified
     */
    public Date getModified() {
        return modified;
    }

    /**
     * @param modified
     */
    protected Date setModified(final Date modified) {
        this.modified = modified;
        return modified;
    }

    /**
     * @return the tags
     */
    public List<Tag> getTags() {
        return tags;
    }

    /**
     * @param tags
     */
    public void setTags(final List<Tag> tags) {
        this.tags = tags;
    }

    /**
     * @return the dataset
     */
    public String getDataset() {
        return dataset;
    }

    /**
     * @param dataset
     */
    public void setDataset(final String dataset) {
        this.dataset = dataset;
    }

    /**
     * @return the uid
     */
    public String getUid() {
        return uid;
    }

    /**
     * @param uid
     */
    public void setUid(final String uid) {
        this.uid = uid;
    }

    /**
     * @return the lId
     */
    public String getLid() {
        return lid;
    }

    /**
     * @param lId
     */
    public void setLid(final String lId) {
        this.lid = lId;
    }

    public boolean isValid() {
        return isValid;
    }

    public void setValid(final boolean value) {
        isValid = value;
    }

    /**
     * @return the links
     */
    public List<Description> getLinks() {
        return links;
    }

    /**
     * @return the links
     */
    // public void setLinks(final List<Description> links) {
    // this.links = links;
    // }
}
